#!/usr/bin/env bash
#
# Copyright (c) 2021 ETH Zurich, University of Bologna
# SPDX-License-Identifier: Apache-2.0
#
# Authors:
# - Andreas Kurth <akurth@iis.ee.ethz.ch>

set -euo pipefail

stderr() {
    printf "$@" >&2
}

# Some authors prefer to not appear with real name and email address in author lists.
declare -A hide=( \
)

# Map each author name to an email address.
declare -A emails=( \
    ["Andreas Kurth"]="akurth@iis.ee.ethz.ch" \
    ["Fabian Schuiki"]="fschuiki@iis.ee.ethz.ch" \
    ["Florian Zaruba"]="zarubaf@iis.ee.ethz.ch" \
    ["Matheus Cavalcante"]="matheusd@iis.ee.ethz.ch" \
    ["Samuel Riedel"]="sriedel@iis.ee.ethz.ch" \
    ["Stefan Mach"]="smach@iis.ee.ethz.ch" \
    ["Wolfgang Rönninger"]="wroennin@iis.ee.ethz.ch" \
)

# Iterate over source files (see `done` line for which files are included).
while IFS= read -r -d $'\0' file; do
    if $(echo "$file" | grep -q '\.svh\?$'); then # SystemVerilog file
        comment_lead='//'
        comment_lead_escaped='\/\/'
    else
        comment_lead='#'
        comment_lead_escaped='#'
    fi
    re_authors="^\\s*${comment_lead}\\s*Authors:\$"

    # If the file does not contain an 'Authors:' paragraph, create one.
    if ! grep -q "$re_authors" "$file"; then
        # Find first line after copyright header.
        copyright_end=$(awk "BEGIN {newparagraph=1;}
        {
            if (newparagraph) {
                if (\$0 ~ /^${comment_lead_escaped}\\s*[cC]opyright/) {
                    newparagraph=0;
                    next
                } else {
                    print NR;
                    exit
                }
            } else if (\$0 ~ /^\\/*$/) {
                newparagraph=1;
                next
            }
        }" "$file")
        # Insert 'Authors:' header.
        sed -i -e "${copyright_end}a${comment_lead} Authors:" "$file"
    fi

    # Find line before and after authors list.
    authors_begin=$(grep -n -m 1 "$re_authors" $file | sed 's/\([0-9]\+\).*/\1/')
    authors_end=$(awk "{if (NR > $authors_begin && \$0 ~ /^\$/) {print NR; exit}}" "$file")

    # Replace author list with information from `git log`.
    tmpfile=$(mktemp)
    {
        sed -n "1,${authors_begin}p" "$file"
        readarray -t changes <<<"$(git log --follow --numstat --format='%an' "$file" | awk '
        BEGIN {totalchange=0; }
        {
            if (NR % 3 == 1) {
                author=$0;
            } else if (NR % 3 == 0) {
                if (!change[author]) {
                    change[author]=0;
                }
                change[author]+=$1;
                totalchange+=$1
                change[author]+=$2;
                totalchange+=$2;
            }
        }
        END {
            print totalchange;
            for (author in change) {
                print change[author] " " author;
            }
        }')"
        totalchange="${changes[0]}"
        authorchanges=()
        for authorchange in "${changes[@]:1}"; do
            name="$(echo "$authorchange" | cut -d' ' -f 2-)"
            change="$(echo "$authorchange" | cut -d' ' -f 1)"
            # Only list authors who have contributed to more than 5% of the changes in the file.
            if test $(( $change * 100 / $totalchange )) -ge 5; then
                authorchanges+=("$change $name")
            fi
        done
        # Sort author with most changes first.
        readarray -t authors < <(printf '%s\n' "${authorchanges[@]}" | sort -nr)
        stderr "$file\n"
        stderr '%s\n' "${authors[@]}"
        stderr '\n'
        readarray -t authors < <(printf '%s\n' "${authors[@]}" | cut -d' ' -f2-)
        for author in "${authors[@]}"; do
            if ! "${hide[$author]:-false}"; then
                if ! test ${emails[$author]+_}; then
                    stderr "Error: Email address of author '$author' unknown!\n"
                    exit 1
                fi
                email="${emails[$author]}"
                author_ascii=$(echo "$author" | sed 's/ö/oe/g')
                if $(echo "$author_ascii" | grep -q -P '[^[:ascii:]]'); then
                    stderr "Author name '$author_ascii' contains a non-ASCII character!\n"
                    exit 1
                fi
                echo "$comment_lead - $author_ascii <$email>"
            fi
        done
        sed -n "$authors_end,\$p" "$file"
    } > "$tmpfile"
    chmod --reference="$file" "$tmpfile" # retain file permissions
    mv "$tmpfile" "$file"

done < <(git ls-tree -r -z --name-only HEAD -- 'include' 'scripts' 'src' 'test' \
    | grep -z -P '\.s(?:vh?|h)$|^(?!.+\.)')
    # left alternative matches files with .sh, .sv, and .svh extensions;
    # right alternative matches files with no extension
